// FilerFrogUpdater.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include <fstream>
#include <string>

#include "FilerFrogUpdater.h"

using namespace std;

FilerFrogUpdater::FilerFrogUpdater():m_CurrentVersion(CURRENT_VERSION),
m_NewVersion(L"N\\A")
{
}

FilerFrogUpdater::~FilerFrogUpdater(){}

void FilerFrogUpdater::SplitVersion(const wstring& ver, int* major, int* middle, int* minor)
{
	size_t pos = ver.find_first_of(L".");
	wstring major_s(ver.substr(0, pos));
	wstring leftof(ver.substr(pos+1, ver.length()));
	pos = leftof.find_first_of(L".");
	wstring middle_s(leftof.substr(0, pos));
	leftof = leftof.substr(pos+1, leftof.length());
	wstring minor_s(leftof.substr(0, pos));

	*major = _wtoi(major_s.c_str());
	*middle = _wtoi(middle_s.c_str());
	*minor = _wtoi(minor_s.c_str());
}

bool FilerFrogUpdater::CheckVersion(const wstring& ver)
{
	int major_new;
	int middle_new;
	int minor_new;
	int major_cur;
	int middle_cur;
	int minor_cur;

	SplitVersion(m_CurrentVersion, &major_cur, &middle_cur, &minor_cur);
	SplitVersion(ver, &major_new, &middle_new, &minor_new);

	if (major_new > major_cur)
	{
		return true;
	}
	else if (major_new == major_cur)
	{
		if (middle_new > middle_cur)
		{
			return true;
		}
		else if (middle_new == middle_cur)
		{
			if (minor_new > minor_cur)
			{
				return true;
			}
		}
	}

	return false;
}

bool FilerFrogUpdater::ParseConfirmFile(const wstring &filePath, wstring& version, wstring& instLink)
{
	wstring tmp(filePath);

	wifstream file(filePath.c_str());

	if (!file.bad())
	{		
		wstring headerStr;
		getline(file, headerStr);

		if (headerStr != L"FilerFrogVersionUpdateFile")
		{
			return false;
		}
		
		wstring versionStr;
		getline(file, versionStr);

		if (versionStr != L"")
		{
			version = versionStr.substr(0, versionStr.length()-1);
		}
		else
		{
			return false;
		}

		wstring linkStr;
		getline(file, linkStr);

		if (linkStr != L"")
		{
			instLink = linkStr.substr(0, linkStr.length()-1);
		}
		else
		{
			return false;
		}
		
		return true;
	}
	else
	{
		return false;
	}	
}

bool FilerFrogUpdater::DownloadFile(const wstring& url, const wstring& folder)
{
	bool retVal = false;

	if (!PathFileExists(folder.c_str()))
	{
		printf("Folder not found !");
		return false;
	}

	HINTERNET hINet = NULL;
	HINTERNET hFile = NULL;

	hINet = InternetOpen(L"FilerFrog Automatic Update", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );

	if (hINet)
	{
		size_t pos = url.find_last_of(L"/");
		wstring fileName(L"");

		if (pos != wstring::npos)
		{
			fileName = url.substr(pos+1, url.length());
		}

		// wstring fileName = L"FilerFrogSetup.msi";

		hFile = InternetOpenUrl(hINet, url.c_str(), NULL, 0, 0, 0 );

		if (hFile)
		{
			char buffer[1024];
			DWORD dwRead;

			wstring target(folder + L"\\" + fileName);
			ofstream out(target.c_str(), ios::binary);

			ZeroMemory(buffer, sizeof(buffer));

			while (InternetReadFile(hFile, buffer, 1023, &dwRead))
			{
				if (dwRead == 0)
				{
					break;
				}

				buffer[dwRead] = 0;
				out.write((char*)&buffer, dwRead);
				memset(buffer, 0, 1024);
			}

			InternetCloseHandle( hFile );
			out.close();

			retVal = true;
		}

		InternetCloseHandle(hINet);
	}
	else
	{
		printf("Error at InternetOpen");
	}

	return retVal;
}

bool FilerFrogUpdater::CheckVersionFromWeb(const wstring& url, const wstring& fileName)
{
	DWORD dwBufSize = 512;
	WCHAR lpPathBuffer[512];

	DWORD dwRetVal = GetTempPath(dwBufSize,     // length of the buffer
		lpPathBuffer); // buffer for path 

	if (dwRetVal > dwBufSize || (dwRetVal == 0))
	{
		printf ("FilerFrogUpdater::checkVersionFromWeb -> GetTempPath failed (%d)\n", GetLastError());
		return false;
	}

	if (!DownloadFile(wstring(url.c_str()), wstring(lpPathBuffer)))
	{
		return false;
	}

	wstring target(wstring(lpPathBuffer) + fileName.c_str());
	wstring version(L"");
	wstring tmp(L"");
	
	if (ParseConfirmFile(target, version, tmp))
	{	
		DeleteFile(target.c_str()); // trying to delete the file... if can't fuck it.
		m_NewVersion = version;
		
		return CheckVersion(version);
	}
	else
	{
		DeleteFile(target.c_str()); // trying to delete the file... if can't fuck it.
		return false;
	}
}

bool FilerFrogUpdater::CheckVersion32()
{
	return CheckVersionFromWeb(wstring(L"http://www.filerfrog.com/assets/files/FF32.ver"), wstring(L"FF32.ver"));
}

bool FilerFrogUpdater::CheckVersion64()
{
	return CheckVersionFromWeb(wstring(L"http://www.filerfrog.com/assets/files/FF64.ver"), wstring(L"FF64.ver"));
}

bool Run(const wstring& app) 
{
	return (int)ShellExecute(NULL, NULL, app.c_str(), NULL, NULL, SW_SHOWNORMAL) > 32;
}


bool FilerFrogUpdater::DownAndRun(const wstring& url, const wstring& fileName)
{
	DWORD dwBufSize = 512;
	WCHAR lpPathBuffer[512];

	DWORD dwRetVal = GetTempPath(dwBufSize,     // length of the buffer
		lpPathBuffer); // buffer for path 
	
	if (dwRetVal > dwBufSize || (dwRetVal == 0))
	{
		printf ("FilerFrogUpdater::checkVersionFromWeb -> GetTempPath failed (%d)\n", GetLastError());
		return false;
	}

	if (DownloadFile(wstring(url.c_str()), wstring(lpPathBuffer)))
	{
		wstring target(wstring(lpPathBuffer) + fileName.c_str());
		wstring tmp(L"");
		wstring instLink(L"");

		ParseConfirmFile(target, tmp, instLink);

		DeleteFile(target.c_str()); // trying to delete the file... if can't fuck it.

		printf("Downloading installation file ...\n");

		if (DownloadFile(instLink, wstring(lpPathBuffer)))
		{
			size_t pos = instLink.find_last_of(L"/");
			wstring instFile(L"");

			if (pos != wstring::npos)
			{
				instFile = instLink.substr(pos+1, instLink.length());
			}

			wstring instLocal(wstring(lpPathBuffer) + L"\\" + instFile);

			return Run(instLocal);
		}
	}

	return false;
}

bool FilerFrogUpdater::DownOnly(const wstring& url, const wstring& fileName, const wstring& folder)
{
	DWORD dwBufSize = 512;
	WCHAR lpPathBuffer[512];

	DWORD dwRetVal = GetTempPath(dwBufSize,     // length of the buffer
		lpPathBuffer); // buffer for path 
	
	if (dwRetVal > dwBufSize || (dwRetVal == 0))
	{
		printf ("FilerFrogUpdater::checkVersionFromWeb -> GetTempPath failed (%d)\n", GetLastError());
		return false;
	}

	if (DownloadFile(wstring(url.c_str()), wstring(lpPathBuffer)))
	{
		wstring target(wstring(lpPathBuffer) + fileName.c_str());
		wstring tmp(L"");
		wstring instLink(L"");
		ParseConfirmFile(target, tmp, instLink);

		DeleteFile(target.c_str()); // trying to delete the file... if can't fuck it.

		printf("Downloading installation file ...\n");

		return DownloadFile(instLink, wstring(folder));
	}

	return false;
}

void FilerFrogUpdater::DownloadAndRunInstallation32()
{
	DownAndRun(wstring(L"http://www.filerfrog.com/assets/files/FF32.ver"), wstring(L"FF32.ver"));
}

void FilerFrogUpdater::DownloadAndRunInstallation64()
{
	DownAndRun(wstring(L"http://www.filerfrog.com/assets/files/FF64.ver"), wstring(L"FF64.ver"));
}

void FilerFrogUpdater::DownloadInstallation32(const wstring& folder)
{
	DownOnly(wstring(L"http://www.filerfrog.com/assets/files/FF32.ver"), wstring(L"FF32.ver"), folder);
}

void FilerFrogUpdater::DownloadInstallation64(const wstring& folder)
{
	DownOnly(wstring(L"http://www.filerfrog.com/assets/files/FF64.ver"), wstring(L"FF64.ver"), folder);
}

void FilerFrogUpdater::RunFile(const wstring& localFile)
{
	Run(localFile);
}

bool CheckGoogleConnection()
{
	bool retVal = false;

	HINTERNET hINet = NULL;
	HINTERNET hFile = NULL;

	hINet = InternetOpen(L"FilerFrog Automatic Update", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );

	if (hINet)
	{
		hFile = InternetOpenUrl(hINet, L"http://www.google.com", NULL, 0, 0, 0 );

		if (hFile)
		{
			printf("Connected to google\n");
			InternetCloseHandle(hFile);
			retVal = true;
		}
		else
		{
			printf("Not Connected to google\n");
		}

		InternetCloseHandle(hINet);
	}
	else
	{
		printf("Not Connected to google\n");
	}

	return retVal;
}

bool CheckConnection()
{
	DWORD state;

	if (InternetGetConnectedState(&state, 0))
	{
		if ((state & INTERNET_CONNECTION_CONFIGURED) == INTERNET_CONNECTION_CONFIGURED)
		{
			printf("Connection configured\n");
		}
		if ((state & INTERNET_CONNECTION_LAN) == INTERNET_CONNECTION_LAN)
		{
			printf("Connection LAN\n");
		}
		if ((state & INTERNET_CONNECTION_MODEM) == INTERNET_CONNECTION_MODEM)
		{
			printf("Connection Modem\n");
		}
		if ((state & INTERNET_CONNECTION_MODEM_BUSY) == INTERNET_CONNECTION_MODEM_BUSY)
		{
			printf("Connection Modem Busy\n");
		}
		if ((state & INTERNET_CONNECTION_OFFLINE) == INTERNET_CONNECTION_OFFLINE)
		{
			printf("Connection Offline\n");
		}
		if ((state & INTERNET_CONNECTION_PROXY) == INTERNET_CONNECTION_PROXY)
		{
			printf("Connection Proxy\n");
		}
		if ((state & INTERNET_RAS_INSTALLED) == INTERNET_RAS_INSTALLED)
		{
			printf("Connection RAS Installed\n");
		}

		return true;
	}

	printf("NO CONNECTION\n");
	return false;
}

bool FilerFrogUpdater::CheckInternetConnection()
{
	return CheckConnection() && CheckGoogleConnection();
}